<?php
require_once(dirname(__FILE__)."/Response/ResponseHeaders.php");
require_once(dirname(__FILE__)."/Response/ResponseStream.php");

/**
 * Compiles information about response
 */
class Response {
	private $strViewPath;
	private $strFileType;
	private $strContentType;
	private $strCharacterEncoding;
	private $headers;
	private $outputStream;
	private $blnIsDisabled;
	
	/**
	 * Detects all information about response
	 */
	public function __construct() {
		$this->strViewPath 			= $this->detectViewPath();
		$this->strFileType			= $this->detectFileType();
		$this->strContentType 		= $this->detectContentType();
		$this->headers 				= new ResponseHeaders();
		$this->outputStream			= new ResponseStream();
	}
	
	/**
	 * Detects view path from XML if set or from page requested by client (or implied by default).
	 * 
	 * @return string
	 */
	private function detectViewPath() {
		$strURL = Servlet::$request->page->getURLPage();
		$strCustomInformation = "pages.".(str_replace("/","_",strtolower($strURL))).".view";
		if(Servlet::$configuration->isAttribute($strCustomInformation)) {
			$strURL = Servlet::$configuration->getAttribute($strCustomInformation);
		}
		return $strURL;
	}
	
	/**
	 * Detects response file type from XML if set or from extension requested by client (or implied by default)
	 * 
	 * @return string
	 */
	private function detectFileType() {
		$strExtension = Servlet::$request->page->getURLExtension();
		$strURL = Servlet::$request->page->getURLPage();
		$strCustomInformation = "pages.".substr(str_replace("/","_",strtolower($strURL)),1).".extension";
		if(Servlet::$configuration->isAttribute($strCustomInformation)) {
			$strExtension = Servlet::$configuration->getAttribute($strCustomInformation);
		}
		return $strExtension;
	}
	
	/**
	 * Detects content type based on extension requested by client (or implied automatically).
	 * 
	 * @throws ServletException
	 * @return string
	 */
	private function detectContentType() {
		$tblAvailableContentTypes = Servlet::$configuration->getAttribute("mime_types");
		if(!isset($tblAvailableContentTypes[$this->strFileType])) throw new ServletException("Mime type not found for: ".$this->strFileType);
		return $tblAvailableContentTypes[$this->strFileType];
	}
	
	/**
	 * Changes view path.
	 * 
	 * @param string $strURL
	 * @return void
	 */
	public function setView($strURL) {
		$this->strViewPath = $strURL;
	}
	
	/**
	 * Gets view path.
	 * 
	 * @return string
	 */
	public function getView() {
		return $this->strViewPath;
	}
	
	/**
	 * Changes response content type.
	 * 
	 * @param string $strContentType
	 * @throws ServletException
	 * @return void
	 */
	public function setContentType($strContentType) {
		$tblAvailableContentTypes = Servlet::$configuration->getAttribute("mime_types");
		if(!in_array($strContentType, $tblAvailableContentTypes)) throw new ServletException("Invalid content type: ".$strContentType);
		$this->strContentType = $strContentType;
	}
	
	/**
	 * Gets response content type.
	 * 
	 * @return string
	 */
	public function getContentType() {
		return $this->strContentType;
	}
	
	/**
	 * Sets response character encoding.
	 * 
	 * @param string $strCharacterEncoding
	 * @return void
	 */
	public function setCharacterEncoding($strCharacterEncoding) {
		$this->strCharacterEncoding = $strCharacterEncoding;
	}
	
	/**
	 * Gets response character encoding.
	 * @return string
	 */
	public function getCharacterEncoding() {
		return $this->strCharacterEncoding;
	}
	
	/**
	 * Gets response stream to work on.
	 * 
	 * @return ResponseStream
	 */
	public function getOutputStream() {
		return $this->outputStream;
	}
	
	/**
	 * Sets a response header.
	 * 
	 * @param string $strName
	 * @param string $strValue
	 * @return void
	 */
	public function setHeader($strName, $strValue) {
		$this->headers->$strName = $strValue;
	}
	
	/**
	 * Gets a response header
	 * 
	 * @param string $strName
	 * @return string
	 */
	public function getHeader($strName) {
		return $this->headers->$strName;
	}
	
	/**
	 * Exits with an error status code.
	 * 
	 * @param integer $intStatusCode
	 * @param string $strError
	 * @return void
	 */
	public function sendError($intStatusCode, $strError) {
		header("HTTP/1.0 ".$intStatusCode." ".$strError);
		exit();
	}
	
	/**
	 * Exits to a new location.
	 * 
	 * @param string $strLocation
	 * @return void
	 */
	public function sendRedirect($strLocation) {
		header($strLocation);
		exit();
	}
	
	/**
	 * Disables response. A disabled response will output nothing.
	 */
	public function disable() {
		$this->blnIsDisabled = true;
	}
	
	/**
	 * Builds a response into output buffer and writes it to output stream.
	 * 
	 * @throws ServletException
	 * @return void
	 */
	public function build() {
		if($this->outputStream->get()) return; // If stream has already been written to, do not build
		if($this->blnIsDisabled) die();	// If response is disabled, no need to go further
		
		// find and run wrapper class
		ob_start();
		Component::runWrapper($this->strFileType);	
		$strContents = ob_get_contents();
		ob_end_clean();
		
		// write string to output stream
		$this->outputStream->write($strContents);
	}
	
	/**
	 * Commits response to client.
	 * 
	 * @return void
	 */
	public function commit() {		
		// set content type
		header("Content-Type: ".$this->getContentType().($this->getCharacterEncoding()?"; charset=".$this->getCharacterEncoding():""));
		
		// set headers
		$tblHeaders = $this->headers->toArray();
		if(sizeof($tblHeaders)>0) {
			foreach($tblHeaders as $strName=>$strValue) {
				header($strName.": ".$strValue);
			}
		}
		
		// show output
		echo $this->outputStream->get();
		
		// terminate execution
		die();
	}
}